﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.IO;
using System.Linq;
using System.Net;
using System.Xml;
using DotNetOpenAuth.OpenId.RelyingParty;

namespace SacNetUG.Models
{
    public class SacNetUGRepository : ISacNetUGRepository
    {
        public IDataContextWrapper Db { get; set; }

        public XmlDocument MissingKids { get; set; }

        public IQueryable<Event> Events;
        public IQueryable<State> States;
        //public IQueryable<Contact> Contacts;
        public IQueryable<User> Users;
        public IQueryable<RSVP> Rsvps;

        public SacNetUGRepository()
        {
            Db = new DataContextWrapper<SacNetUGDataContext>();
            Events = Db.Table<Event>();
            States = Db.Table<State>();
            //Contacts = Db.Table<Contact>();
            Users = Db.Table<User>();
            Rsvps = Db.Table<RSVP>();
        }

        public SacNetUGRepository(IDataContextWrapper dataContext)
        {
            Db = dataContext;
            Events = Db.Table<Event>();
        }

        //NOTE: events will be out of order if the index on the date column is missing
        public IQueryable<Event> GetRecentEvents()
        {
            var pastEvent = Events.Where(e => e.StartDate < DateTime.Now).OrderByDescending(e => e.StartDate).Take(1);
            var futureEvents = GetFutureEvents().Take(3);

            return pastEvent.Concat(futureEvents);
        }

        //NOTE: events will be out of order if the index on the date column is missing
        public IQueryable<Event> GetFutureEvents()
        {
            return Events.Where(e => e.StartDate.Date >= DateTime.Today);
        }

        public Event GetEvent(int eventId)
        {
            return Events.FirstOrDefault(e => e.EventId == eventId);
        }

        public Event GetNextEvent()
        {
            return GetFutureEvents()
                .OrderBy(e => e.StartDate)
                .Take(1)
                .SingleOrDefault();
        }

        public IQueryable<State> GetStates(int page)
        {
            var pageSize = 10;
            return States
                .OrderBy(s => s.Id)
                .Skip(pageSize * (page - 1))
                .Take(pageSize);
        }

        public int GetStatePageCount()
        {
            var pageSize = 10;
            var stateCount = States.Count();
            var total = stateCount / pageSize;
            if ((stateCount % pageSize) > 0)
                total++;
            return total;
        }

        public User GetUser(int id)
        {
            return Users.FirstOrDefault(u => u.Id == id);
        }

        private static readonly Func<SacNetUGDataContext, IQueryable<string>> CmsRoutesCompiled =
            CompiledQuery.Compile((SacNetUGDataContext db) =>
                                  from c in db.Contents
                                  select (c.Controller + "." + c.Action).ToLower());

        public HashSet<string> GetCmsRoutes()
        {
            //Uses a compiled query (above)
            return new HashSet<string>(CmsRoutesCompiled(new SacNetUGDataContext()).ToList());
        }

        //public bool Contains(Contact contact)
        //{
        //    return Contacts
        //           .Where(c => c.Email == contact.Email && c.Comments == contact.Comments)
        //           .Count() > 0;
        //}

        //public void Add(Contact contact)
        //{
        //    Db.InsertOnSubmit(contact);
        //}

        public void Save()
        {
            Db.SubmitChanges();
        }

        public User GetUserByOpenId(string openId)
        {
            return Users.SingleOrDefault(u => u.AuthID == openId);
        }

        public void Add(User user)
        {
            Db.InsertOnSubmit(user);
        }

        public User GetUserByOpenId(IAuthenticationResponse response)
        {
            var openIdUser = Users.FirstOrDefault(u => u.AuthID == response.ClaimedIdentifier.OriginalString);
            if (openIdUser == null)
                return GetUserByOpenId(response.FriendlyIdentifierForDisplay);
            return openIdUser;
        }

        public RSVP GetRsvp(User user, int eventId, bool willAttend)
        {
            return Rsvps
                .Where(r => r.User.Id == user.Id)
                .Where(r => r.EventId == eventId)
                .SingleOrDefault(r => r.WillAttend == willAttend);
        }

        public RSVP GetRsvp(User user, int eventId)
        {
            return Rsvps
                .Where(r => r.User.Id == user.Id)
                .SingleOrDefault(r => r.EventId == eventId);
        }

        public User GetUser(string authId)
        {
            return Users.FirstOrDefault(u => u.AuthID == authId);
        }

        public bool IsUserRegistered(string id)
        {
            var user = GetUser(id);
            return user != null;
        }

        public void AddUser(RegisterModel registerModel)
        {
            var newUser = new User
            {
                FirstName = registerModel.FirstName,
                LastName = registerModel.LastName,
                EmailAddress = registerModel.Email,
                AuthID = registerModel.AuthId
            };

            Add(newUser);
            Save();
        }

        #region Missing Kids

        public List<MissingKid> GetMissingKids()
        {
            if (MissingKids == null)
            {
                MissingKids = new XmlDocument();
                MissingKids.LoadXml(GetXmlResults());
            }

            var nodes = MissingKids.SelectNodes("//location");

            if (nodes == null) return new List<MissingKid>();

            return (from XmlNode node in nodes select new MissingKid(node)).ToList();
        }

        public string GetXmlResults()
        {
            HttpWebRequest webRequest = GetWebRequest("http://www.missingkidsmap.com/read.php?state=ZZ");
            var response = (HttpWebResponse)webRequest.GetResponse();
            string jsonResponse;
            using (var sr = new StreamReader(response.GetResponseStream()))
            {
                jsonResponse = sr.ReadToEnd();
            }
            return jsonResponse;
        }

        private HttpWebRequest GetWebRequest(string formattedUri)
        {
            // Create the request’s URI.
            var serviceUri = new Uri(formattedUri, UriKind.Absolute);

            // Return the HttpWebRequest.
            return (HttpWebRequest)WebRequest.Create(serviceUri);
        }
        #endregion
    }
}